package ch.elca.lol.puissance4.game;

import ch.elca.lol.puissance4.board.Board;
import ch.elca.lol.puissance4.player.Player;

/** A game of connect four with two players. */
public class Game {
	private boolean verbose = true;
	private long delay = 500;
	
	public static final int P1_WIN = 1;
	public static final int P2_WIN = -1;
	public static final int STALEMATE = 0;
	public static final int UNFINISHED = -2;
	
	private final Player p1;
	private final Player p2;
	private Board board;
	private int result = UNFINISHED;
	
	public Game(Player p1, Player p2, Board b) {
		this.p1 = p1;
		this.p2 = p2;
		this.board = b;
	}
	
	public void configure(boolean verbosity, int delay) {
		this.verbose = verbosity;
		this.delay = delay;
	}
	
	public void play() {
		p1.setToken(Token.O);
		p2.setToken(Token.X);
		
		print("Game started.\n");
		print(board.toString() + "\n");
		
		for(;;) {
			if(playOneTurn(p1, Token.O, p2))
				break;
			if(playOneTurn(p2, Token.X, p1))
				break;
		}
		
		storeResult();
		print(getResultString() + "\n");
	}
	
	// TODO limit time given to AIs (run them in a thread, limit priviledges)
	private boolean playOneTurn(Player p, Token sq, Player other) {
		Delayer delayer = new Delayer();
		delayer.tick();
		
		int col = -1;
		col = p.play(board);
		
		// Verify move validity
		while(!board.isPlayable(col)) {
			throw new RuntimeException(p + " tried invalid move " + col + " on [" + board.getClass().getSimpleName()
					+ "] \n" + board + "\n");
		}
		
		// Actually play
		board = board.play(col, sq);
		
		print(p + " [" + sq + "] played:\n");
		print(board + "\n\n");
		
		boolean over = board.isGameOver();
		if(!over)
			delayer.delay(delay);
		
		other.played(col);
		return over;
	}
	
	private void storeResult() {
		Token winner = board.getWinner();
		if(winner == Token.O)
			result = P1_WIN;
		else if(winner == Token.X)
			result = P2_WIN;
		else
			result = STALEMATE;
	}
	
	public int getResult() {
		return result;
	}
	
	public String getResultString() {
		switch(getResult()) {
			case STALEMATE:
				return "Stalemate.";
			case P1_WIN:
				return p1 + " [" + Token.O + "] has won.";
			case P2_WIN:
				return p2 + " [" + Token.X + "] has won.";
			default:
				return "Game hasn't ended yet.";
		}
	}
	
	private void print(String s) {
		if(verbose) {
			System.out.print(s);
		}
	}
}
